
#ifndef __avmplus_avmbind_hpp__
#define __avmplus_avmbind_hpp__

#define DEV_BIND extern "C" __declspec(dllexport) 

#include "avmrt.h"
#include "avmrt-bind.h"

namespace avmbind
{

	class String
	{
	public:
		String();//unimplemented	

		inline void append(String *src)
		{
			::avmbind_String_append( this,src);
		}

		inline int getLength()
		{
			return avmbind_String_getLength( this );
		}		
		
		inline Atom atom()
		{
			return ::avmbind_String_atom( this );
		}

		inline char* toUTF8()
		{
			return avmbind_String_toCstr( this );
		}

		inline wchar* toUTF16()
		{
			return avmbind_String_toUTF16( this );
		}

		static String *construct( char *str, int len = -1 )
		{
			return (avmbind::String*)avmbind_String( str, len );
		}

	};
	
	class Object
	{
	public:
		Object( );//unimplemented	
	
		inline Atom atom()
		{
			return ::avmbind_Object_atom( (ScriptObject*)this );
		}

		inline Atom getProperty( char *name )
		{
			::avm_Object_getProperty( atom(), name );
		}
		
		inline Atom setProperty( char *name, Atom value )
		{
			::avm_Object_setProperty( atom(), name, value );
		}

		Atom callProperty( char *name, int argc, Atom *argv )
		{
			Atom _argv[1] = {0};

			if( !argv )
				argv = _argv;
			
			return ::avm_Object_callProperty( atom(), name, argc, argv );
		}
		inline void *getDataPointer()
		{
			return ::avmbind_Object_getDataPointer( (ScriptObject*)this );
		}		
		
		static Object *construct( )
		{
			return (avmbind::Object*)avmbind_Object( );
		}
	};	
	
	class Class : public Object
	{
	public:
		Class( );//unimplemented	
	
		Object *construct(int argc, Atom* argv)
		{
			return (avmbind::Object*)::avm_atom_toObject( ::avm_Class_construct( atom(), argc, argv ) );
		}
	};

	class Function : public Class
	{
	public:
		Function( );//unimplemented	
	
		Atom construct(int argc, Atom* argv)
		{
			return 0;
		}

		Atom call(int argc, Atom* argv)
		{
			return avm_Function_call( atom(), argc, argv );
		}
	};

	template<class T>
	class NativeObject : public Object
    {
	public:		
		
		T operator->() const
        {
			return (T)::avmbind_Object_getDataPointer( (ScriptObject*)this );
        }
	};
	
	class Array : public Object
	{
	
	public:
		
		inline Atom getItem( int index )
		{
			return avmbind_Array_getItem( (ScriptObject*)this, index );
		}		
		
		inline void setItem( int index, Atom value )
		{
			avmbind_Array_setItem( (ScriptObject*)this, index, value );
		}

		inline int getLength( )
		{
			return avmbind_Array_getLength( (ScriptObject*)this );
		}		

		inline void push( Atom a )
		{
			avmbind_Array_push( (ScriptObject*)this, a );
		}	

		inline Atom pop( )
		{
			return avmbind_Array_pop( (ScriptObject*)this );
		}	
		
		static Array *construct( int argc=0, Atom *argv=0 )
		{
			return (avmbind::Array*)avm_atom_toObject( avm_Array( argc, argv ) );
		}
	};

	class Vector : public Object
	{
	
	public:
		
		inline int getLength( )
		{
			return avmbind_Vector_getLength( (ScriptObject*)this );
		}		

		inline void push( Atom a )
		{
			avmbind_Vector_push( (ScriptObject*)this, a );
		}	

		inline Atom pop( )
		{
			return avmbind_Vector_pop( (ScriptObject*)this );
		}	
		
	
	};
	
	class IntVector : public Vector
	{
	
	public:
		
		inline int getItem( int index )
		{
			return avmbind_IntVector_getItem( (ScriptObject*)this, index );
		}		
		
		inline void setItem( int index, int value )
		{
			avmbind_IntVector_setItem( (ScriptObject*)this, index, value );
		}

	
	};	
	
	class DoubleVector : public Vector
	{
	
	public:
		
		inline double getItem( int index )
		{
			return avmbind_DoubleVector_getItem( (ScriptObject*)this, index );
		}		
		
		inline void setItem( int index, double value )
		{
			avmbind_DoubleVector_setItem( (ScriptObject*)this, index, value );
		}

	
	};

	template<class T>
	class ObjectHandle
	{
	protected:
		T *o;
	
	public:
		ObjectHandle( ScriptObject *_o ) : o( _o )
		{

		}		
		
		ObjectHandle( Atom _a ) 
		{
			o = (T*)::avm_atom_toObject( _a );
		}		
		
		T* operator->() const
        {
			return (T*)o;
        }
	};

}


#endif